package com.mp.approvalreq.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.mp.approvalreq.dao.*;
import com.mp.approvalreq.dao.impl.*;
import com.mp.approvalreq.entity.*;
import com.mp.approvalreq.entity.dto.*;
import com.mp.approvalreq.entity.po.ComponentGroup;
import com.mp.approvalreq.entity.po.GlobalSetting;
import com.mp.approvalreq.entity.vo.Component;
import com.mp.approvalreq.service.SelectApprovalServiceServant;
import com.mp.approvalreq.util.*;
import com.mp.approvalreq.util.ValidateUtil;
import com.mp.user.entity.User;
import com.plusmoney.exception.RpcServerLogicalException;
import com.plusmoney.jdbc.util.DBUtils;
import com.plusmoney.util.*;
import com.plusmoney.util.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;


public class SelectApprovalServantImpl implements SelectApprovalServiceServant {

    private static final Logger logger = LoggerFactory.getLogger(SelectApprovalServantImpl.class);


    @Override
    public List<Integer> getRequestIdByAncestorId(Integer id) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            RequestDao requestDao = new RequestDaoImpl(connection);
            return requestDao.selectRequestIdsByAncestorId(id);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public RequestCostDTO getApprovalsCostAmount(Integer companyId, String month) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectApprovalDao selectApprovalDao = DaoFactory.getSelectApprovalDao(connection);
            SelectTemplateDao selectTemplateDao = DaoFactory.getSelectTemplateDao(connection);
            ComponentDao componentDao = new ComponentImpl(connection);

            checkParam(companyId, month);

            List<TemplateDTO> costTemplateDTOs = selectTemplateDao.getAssociateCostTemplateDTOs(companyId);

            List<RequestInfoDTO> requestInfoDTOS = new ArrayList<>();

            if (ListHelper.isNotNullEmpty(costTemplateDTOs)) {
                List<Integer> templateIds = TemplateUtils.getTemplateIds(costTemplateDTOs);
                requestInfoDTOS = selectApprovalDao.getApprovalsCostByMonth(companyId, month, templateIds);

                if (ListHelper.isNotNullEmpty(requestInfoDTOS)) {
                    List<Integer> requestIds = ApprovalUtils.getRequestIds(requestInfoDTOS);

                    Map<Integer, List<TemplateComponent>> componentMap = componentDao.selectComponentMapByRequestIds(Utils.list2string(requestIds));

                    ApprovalUtils.setApprovalsCostMoney(requestInfoDTOS, componentMap, costTemplateDTOs);
                }
            }

            return initRequestCostDTOs(requestInfoDTOS);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private RequestCostDTO initRequestCostDTOs(List<RequestInfoDTO> requestInfoDTOS) {
        RequestCostDTO requestCostDTO = new RequestCostDTO();

        BigDecimal totalCost = BigDecimal.ZERO;
        List<Integer> requestIds = new ArrayList<>(requestInfoDTOS.size());

        for (RequestInfoDTO requestInfoDTO : requestInfoDTOS) {
            totalCost = totalCost.add(requestInfoDTO.getCostMoney());
            requestIds.add(requestInfoDTO.getRequestId());
        }

        requestCostDTO.setTotalCost(totalCost.toString());
        requestCostDTO.setRequestCount(requestIds.size());
        if (ListHelper.isNotNullEmpty(requestIds)) {
            requestCostDTO.setRequestIds(ListHelper.list2string(requestIds));
        }

        return requestCostDTO;
    }

    private void checkParam(Integer companyId, String month) {
        if (Utils.isNull(companyId)) {
            throw new RpcServerLogicalException(1, "公司id不能为空");
        }

        if (StringUtils.isEmpty(month)) {
            throw new RpcServerLogicalException(1, "月份参数不能为空");
        }

        if (!ValidateUtil.isValidMonth(month)) {
            throw new RpcServerLogicalException(1, "月份参数格式不正确");
        }
    }


    @Override
    public List<TemplateDTO> getMyRequestFlowAndCc(Integer companyId, Integer contactId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectTemplateDao selectTemplateDao = DaoFactory.getSelectTemplateDao(connection);

            List<TemplateDTO> templateDTOs = selectTemplateDao.selectCompanyTemplates(companyId);

            List<TemplateDTO> myTemplateDTOs = new ArrayList<>();
            if (ListHelper.isNotNullEmpty(templateDTOs)) {
                shiftMyRequestFlowAndCc(myTemplateDTOs, contactId, templateDTOs);

                List<TemplateDTO> conditionFlowDTOs = getTemplateConditionFlowDTOs(templateDTOs);
                if (ListHelper.isNotNullEmpty(conditionFlowDTOs)) {
                    String templateIds = getTemplateIds(conditionFlowDTOs);

                    Map<Integer, List<ConditionFlowDTO>> conditionFlowTemplateDTOMap =
                            selectTemplateDao.getConditionFlowTemplateDTOs(companyId, templateIds);
                    // 筛选条件审批流
                    shiftMyRequestConditionFlows(myTemplateDTOs, conditionFlowTemplateDTOMap, contactId, conditionFlowDTOs);
                }
            }

            return myTemplateDTOs;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }


    private void shiftMyRequestConditionFlows(List<TemplateDTO> myTemplateDTOs, Map<Integer, List<ConditionFlowDTO>> map, Integer contactId, List<TemplateDTO> conditionFlowDTOs) {
        for (List<ConditionFlowDTO> conditionFlowDTOList : map.values()) {
            boolean flag = false;
            for (ConditionFlowDTO conditionFlowDTO : conditionFlowDTOList) {
                List<Integer> flows = ListHelper.string2IntegerList(conditionFlowDTO.getRequestFlow());
                if (flows.contains(contactId)) {
                    for (TemplateDTO templateDTO : conditionFlowDTOs) {
                        if (templateDTO.getTemplateId().equals(conditionFlowDTO.getTemplateId())) {
                            templateDTO.setRequestFlow(conditionFlowDTO.getRequestFlow());
                            myTemplateDTOs.add(templateDTO);
                            flag = true;
                            break;
                        }
                    }
                }
                if (flag) {
                    break;
                }
            }
        }
    }

    private String getTemplateIds(List<TemplateDTO> conditionFlowDTOs) {
        List<Integer> templateIds = new ArrayList<>();

        for (TemplateDTO templateDTO : conditionFlowDTOs) {
            templateIds.add(templateDTO.getTemplateId());
        }

        return ListHelper.list2string(templateIds);
    }


    private List<TemplateDTO> getTemplateConditionFlowDTOs(List<TemplateDTO> templateDTOs) {
        List<TemplateDTO> conditionTemplateDTOs = new ArrayList<>();

        for (TemplateDTO templateDTO : templateDTOs) {
            if (templateDTO.getRequestFlow().equals(RequestFlowType.CONDITION)) {
                conditionTemplateDTOs.add(templateDTO);
            }
        }

        return conditionTemplateDTOs;
    }

    private void shiftMyRequestFlowAndCc(List<TemplateDTO> myTemplateDTOs, Integer contactId, List<TemplateDTO> templateDTOs) throws Throwable {
        for (TemplateDTO templateDTO : templateDTOs) {
            boolean flag = false;
            List<Integer> requestFlows = ListHelper.string2IntegerList(templateDTO.getRequestFlow());
            if (requestFlows.contains(contactId)) {
                myTemplateDTOs.add(templateDTO);
                flag = true;
            }

            if (!flag) {
                if (StringUtils.isNotEmpty(templateDTO.getTemplateCc())) {
                    List<Integer> templateCcs = ListHelper.string2IntegerList(templateDTO.getTemplateCc());
                    if (templateCcs.contains(contactId)) {
                        myTemplateDTOs.add(templateDTO);
                    }
                }
            }
        }
    }

    @Override
    public List<GeneralRequestDTO> getMyGeneralRequestFlows(User user, String projectIds) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectApprovalDao selectApprovalDao = DaoFactory.getSelectApprovalDao(connection);

            List<GeneralRequestDTO> myGeneralRequestDTOS = new ArrayList<>();

            List<GeneralRequestDTO> generalRequestDTOS = selectApprovalDao
                    .getProjectGeneralRequestFlows(user.getCompanyId(), ListHelper.string2IntegerList(projectIds));

            if (ListHelper.isNotNullEmpty(generalRequestDTOS)) {
                // 筛出审批流
                shiftMyRequestFlows(user.getContactId(), myGeneralRequestDTOS, generalRequestDTOS);

                List<GeneralRequestDTO> generalConditionFlowDTOs = getGeneralConditionFlowDTOs(generalRequestDTOS);
                if (ListHelper.isNotNullEmpty(generalConditionFlowDTOs)) {
                    List<Integer> generalConditionFlowIdList = getGeneralConditionFlowIdList(generalConditionFlowDTOs);

                    Map<Integer, List<GeneralConditionFlowDTO>> generalConditionFlowDTOMap = selectApprovalDao
                            .getGeneralConditionFlowDTOs(user.getCompanyId(), generalConditionFlowIdList);

                    // 筛出条件审批流
                    shiftMyRequestFlows(myGeneralRequestDTOS, generalConditionFlowDTOMap, user.getContactId(), generalConditionFlowDTOs);
                }
            }

            return myGeneralRequestDTOS;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private void shiftMyRequestFlows(List<GeneralRequestDTO> myGeneralRequestDTOS, Map<Integer, List<GeneralConditionFlowDTO>> generalConditionFlowDTOMap, Integer contactId, List<GeneralRequestDTO> generalConditionFlowDTOs) {
        for (List<GeneralConditionFlowDTO> generalConditionFlowDTOList : generalConditionFlowDTOMap.values()) {
            boolean flag = false;
            for (GeneralConditionFlowDTO generalConditionFlowDTO : generalConditionFlowDTOList) {
                List<String> flows = ListHelper.string2NumStringList(generalConditionFlowDTO.getRequestFlow());
                if (flows.contains(String.valueOf(contactId))) {
                    for (GeneralRequestDTO generalRequestDTO : generalConditionFlowDTOs) {
                        if (generalRequestDTO.getId().equals(generalConditionFlowDTO.getGeneralFlowId())) {
                            generalRequestDTO.setAllJudger(generalConditionFlowDTO.getRequestFlow());
                            myGeneralRequestDTOS.add(generalRequestDTO);
                            flag = true;
                            break;
                        }
                    }
                }
                if (flag) {
                    break;
                }
            }
        }
    }

    private void shiftMyRequestFlows(Integer contactId, List<GeneralRequestDTO> myGeneralRequestDTOS, List<GeneralRequestDTO> generalRequestDTOS) {
        for (GeneralRequestDTO generalRequestDTO : generalRequestDTOS) {
            List<String> flows = ListHelper.string2NumStringList(generalRequestDTO.getAllJudger());
            if (flows.contains(String.valueOf(contactId))) {
                myGeneralRequestDTOS.add(generalRequestDTO);
            }
        }
    }

    private List<GeneralRequestDTO> getGeneralConditionFlowDTOs(List<GeneralRequestDTO> generalRequestDTOS) {
        List<GeneralRequestDTO> generalConditionFlowDTOs = new ArrayList<>();

        for (GeneralRequestDTO generalRequestDTO : generalRequestDTOS) {
            if (generalRequestDTO.getAllJudger().equals(RequestFlowType.CONDITION)) {
                generalConditionFlowDTOs.add(generalRequestDTO);
            }
        }

        return generalConditionFlowDTOs;
    }

    private List<Integer> getGeneralConditionFlowIdList(List<GeneralRequestDTO> generalRequestDTOS) {
        List<Integer> generalConditionFlowIds = new ArrayList<>();

        for (GeneralRequestDTO generalRequestDTO : generalRequestDTOS) {
            generalConditionFlowIds.add(generalRequestDTO.getId());
        }

        return generalConditionFlowIds;
    }


    /**
     * 输入: companyInfoId, date:yyyy-MM-dd
     * 输出: startTime,endTime,requestId
     * 获取某人某天的加班信息
     */
    @Override
    public List<RequestInfoDTO> getWorkTimeInfo(Integer companyInfoId, String date) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            checkWorkDateParam(companyInfoId, date);

            SelectTemplateDao selectTemplateDao = DaoFactory.getSelectTemplateDao(connection);
            SelectApprovalDao selectApprovalDao = DaoFactory.getSelectApprovalDao(connection);
            ComponentDao componentDao = new ComponentImpl(connection);

            List<RequestInfoDTO> requestInfoDTOs = new LinkedList<>();

            List<RequestInfoDTO> workTimeRequests = selectApprovalDao.getOverWorkTimeRequests(companyInfoId);
            if (ListHelper.isNotNullEmpty(workTimeRequests)) {
                Integer companyId = workTimeRequests.get(0).getCompanyId();

                Map<Integer, TemplateDTO> templateDTOMap = selectTemplateDao.getTemplateDTOMap(companyId, ListHelper.getTemplateIdList(workTimeRequests));
                List<Integer> requestIds = ListHelper.getRequestIds(workTimeRequests);
                Map<Integer, List<TemplateComponent>> componentsMap = componentDao.selectComponentMapByRequestIds(Utils.list2string(requestIds));

                shiftSpecifiedDateRequestDTO(workTimeRequests, date, componentsMap, requestInfoDTOs, templateDTOMap);
                wrapPersonInfo(workTimeRequests, requestInfoDTOs);

                ApprovalListUtils.setRelaPeopleNames(requestInfoDTOs, companyId);
            }

            return requestInfoDTOs;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private void wrapPersonInfo(List<RequestInfoDTO> workTimeRequests, List<RequestInfoDTO> requestInfoDTOs) {
        for (RequestInfoDTO requestInfoDTO : requestInfoDTOs) {
            for (RequestInfoDTO workTimeRequest : workTimeRequests) {
                if (requestInfoDTO.getRequestId().equals(workTimeRequest.getRequestId())) {
                    requestInfoDTO.setApplicant(workTimeRequest.getApplicant());
                    requestInfoDTO.setRelaPeopleContactIds(workTimeRequest.getRelaPeopleContactIds());
                    requestInfoDTO.setTemplateId(workTimeRequest.getTemplateId());
                    requestInfoDTO.setCompanyId(workTimeRequest.getCompanyId());
                    requestInfoDTO.setRequestName(workTimeRequest.getRequestName());
                    requestInfoDTO.setRequestTime(workTimeRequest.getRequestTime());
                    requestInfoDTO.setFinished(workTimeRequest.getFinished());
                    requestInfoDTO.setRequestAncestorId(workTimeRequest.getRequestAncestorId());
                    requestInfoDTO.setVersion(workTimeRequest.getVersion());
                    requestInfoDTO.setDefaultType(workTimeRequest.getDefaultType());
                    break;
                }
            }
        }
    }

    private void checkWorkDateParam(Integer companyInfoId, String date) {
        if (Utils.isNull(companyInfoId)) {
            throw new RpcServerLogicalException(1, "id不能为空");
        }

        if (StringUtils.isEmpty(date)) {
            throw new RpcServerLogicalException(1, "日期参数不能为空");
        }

        if (!ValidateUtil.isValidDate(date)) {
            throw new RpcServerLogicalException(1, "日期参数格式不正确");
        }
    }

    private void shiftSpecifiedDateRequestDTO(List<RequestInfoDTO> workTimeRequests, String date,
                                              Map<Integer, List<TemplateComponent>> componentsMap, List<RequestInfoDTO> requestInfoDTOs, Map<Integer, TemplateDTO> templateDTOMap) throws ParseException {

        SimpleDateFormat sdf = DateUtils.getSimpleDateFormat(DateUtils.YMD);

        for (List<TemplateComponent> components : componentsMap.values()) {
            Integer requestId = components.get(0).getRequestId();
            Integer templateId = components.get(0).getTemplateId();
            List<String> times = ApprovalUtils.getTimeList(components, Template.WORK_OVERTIME);

            String startTime = sdf.format(sdf.parse(times.get(0)).getTime());
            String endTime = sdf.format(sdf.parse(times.get(1)).getTime());
            String outPosition = getOutPosition(requestId, workTimeRequests);
            String location = getLocation(components);
            Integer isRelatedWorkTime = templateDTOMap.get(templateId).getIsRelatedWorkTime();
            String color = templateDTOMap.get(templateId).getTemplateColor();

            //  start <= data <= endtime
            if (date.compareTo(startTime) >= 0 && date.compareTo(endTime) <= 0) {
                RequestInfoDTO requestInfoDTO = new RequestInfoDTO();
                requestInfoDTO.setRequestId(requestId);
                requestInfoDTO.setStartTime(times.get(0));
                requestInfoDTO.setEndTime(times.get(1));
                requestInfoDTO.setOutPosition(outPosition);
                requestInfoDTO.setLocation(location);
                requestInfoDTO.setIsRelatedWorkTime(isRelatedWorkTime);
                requestInfoDTO.setTemplateColor(color);
                requestInfoDTO.setComponents(components);

                requestInfoDTOs.add(requestInfoDTO);
            }
        }
    }

    private String getLocation(List<TemplateComponent> components) {
        String location = null;

        for (TemplateComponent component : components) {
            // 地点
            if (component.getNum() == 4 && component.getType() == 6) {
                location = component.getValue();
                break;
            }
        }

        return location;
    }

    private String getOutPosition(Integer requestId, List<RequestInfoDTO> workTimeRequests) {
        String outPosition = null;
        for (RequestInfoDTO requestInfoDTO : workTimeRequests) {
            // 经纬度
            if (requestInfoDTO.getRequestId().equals(requestId)) {
                outPosition = requestInfoDTO.getOutPosition();
            }
        }
        return outPosition;
    }


    @Override
    public TemplateDTO getTemplateDTO(Integer companyId, Integer templateId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectTemplateDao selectTemplateDao = DaoFactory.getSelectTemplateDao(connection);

            return selectTemplateDao.getTemplateDTO(companyId, templateId);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }


    @Override
    public TemplateDTO getDefaultTemplateDTO(Integer defaultType) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectTemplateDao selectTemplateDao = DaoFactory.getSelectTemplateDao(connection);

            return selectTemplateDao.getTemplateDTO(defaultType);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }


    @Override
    public RequestDTO getRequestDTO(Integer companyId, Integer requestId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectApprovalDao selectApprovalDao = DaoFactory.getSelectApprovalDao(connection);

            return selectApprovalDao.getRequestDetail(companyId, requestId);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }


    @Override
    public ComponentGroupDTO getComponentGroupDTOById(Integer companyId, Integer componentGroupId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectTemplateDao selectTemplateDao = DaoFactory.getSelectTemplateDao(connection);

            ComponentGroup componentGroup = selectTemplateDao.selectComponentGroupById(companyId, componentGroupId);

            if (Utils.isNull(componentGroup.getId())) {
                throw new RpcServerLogicalException(1, "组件集不存在或已被删除");
            }

            return BeanUtils.copyProperties(ComponentGroupDTO.class, componentGroup);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }


    @Override
    public List<ComponentGroupDTO> getComponentGroupDTOs(Integer companyId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectTemplateDao selectTemplateDao = DaoFactory.getSelectTemplateDao(connection);

            List<ComponentGroup> list = selectTemplateDao.selectComponentGroupList(companyId);

            if (ListHelper.isNotNullEmpty(list)) {
                return BeanUtils.pos2dtos(list, ComponentGroupDTO.class);
            }

            return new ArrayList<>();
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public List<ComponentGroupDTO> getComponentGroupInfoDTOs(Integer companyId, String componentGroupIds) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectTemplateDao selectTemplateDao = DaoFactory.getSelectTemplateDao(connection);

            List<ComponentGroup> list = selectTemplateDao.selectComponentGroupInfoList(companyId, componentGroupIds);

            if (ListHelper.isNotNullEmpty(list)) {
                return BeanUtils.pos2dtos(list, ComponentGroupDTO.class);
            }

            return new ArrayList<>();
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }


    @Override
    public List<ApprovalCost> getApprovalCost(Integer companyId, String requestIds) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectApprovalDao selectApprovalDao = DaoFactory.getSelectApprovalDao(connection);
            ComponentDao componentDao = new ComponentImpl(connection);

            List<ApprovalCost> approvalCosts = selectApprovalDao.getCostApprovals(companyId, requestIds);

            if (Utils.isEmpty(approvalCosts)) {
                return approvalCosts;
            }

            List<Integer> requestIdList = getRequestIds(approvalCosts);
            Map<Integer, List<TemplateComponent>> contentMap = componentDao.selectComponentMapByRequestIds(Utils.list2string(requestIdList));
            for (Map.Entry<Integer, List<TemplateComponent>> entry : contentMap.entrySet()) {
                List<TemplateComponent> list = new ArrayList<>();
                for (TemplateComponent component : entry.getValue()) {
                    if (component.getType() == ContentType.MONEY || component.getType() == ContentType.TOTAL_MONEY) {
                        list.add(component);
                    }
                }
                contentMap.put(entry.getKey(), list);
            }

            for (ApprovalCost approvalCost : approvalCosts) {
                List<TemplateComponent> contents = contentMap.get(approvalCost.getRequestId());
                if (Utils.isNotEmpty(contents)) {
                    BigDecimal costMoney = getCostMoney(approvalCost, contents);
                    approvalCost.setCostMoney(costMoney);
                } else {
                    logger.info("requestId:{}", approvalCost.getRequestId());
                }
            }

            return approvalCosts;
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }


    private BigDecimal getCostMoney(ApprovalCost approvalCost, List<TemplateComponent> contents) {
        if (approvalCost.getTemplateType() == Template.EXPENSES) {
            if (StringUtils.isNotEmpty(approvalCost.getTotalMoney())
                    && approvalCost.getTotalMoney().length() < 10) {
                return new BigDecimal(approvalCost.getTotalMoney());
            }
        }

        if (StringUtils.isEmpty(approvalCost.getAnalysisNum())) {
            for (TemplateComponent content : contents) {
                if (StringUtils.isNotEmpty(content.getValue()) && content.getValue().length() < 10) {
                    if (ValidateUtil.isInteger(content.getValue())) {
                        return new BigDecimal(content.getValue());
                    }
                }
            }

        } else {
            for (TemplateComponent content : contents) {
                if (approvalCost.getAnalysisNum().equals(String.valueOf(content.getNum()))) {
                    if (StringUtils.isNotEmpty(content.getValue()) && content.getValue().length() < 10) {
                        if (ValidateUtil.isInteger(content.getValue())) {
                            return new BigDecimal(content.getValue());
                        }
                    }
                }
            }
        }
        return null;
    }

    private List<Integer> getRequestIds(List<ApprovalCost> approvalCosts) {
        List<Integer> requestIds = new ArrayList<>();
        for (ApprovalCost approvalCost : approvalCosts) {
            requestIds.add(approvalCost.getRequestId());
        }
        return requestIds;
    }


    @Override
    public void initGlobalSetting(Integer companyId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            GlobalSettingDao globalSettingDao = new GlobalSettingDaoImpl(connection);

            GlobalSetting globalSetting = globalSettingDao.selectGlobalSetting(companyId);
            // 不存在时再进行初始化
            if (Utils.isNull(globalSetting.getId())) {
                GlobalSetting defaultGlobalSetting = new GlobalSetting();
                defaultGlobalSetting.setCompanyId(companyId);
                defaultGlobalSetting.setDuplicateStrategy(DuplicateStrategy.REMAIN_LAST_ITEM);
                DBUtils.begin(connection);
                globalSettingDao.insertDuplicateStrategy(defaultGlobalSetting);
                DBUtils.commit(connection);
            }

        } catch (Throwable e) {
            DBUtils.release(connection);
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }


    @Override
    public GlobalSettingDTO getGlobalSetting(Integer companyId) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            GlobalSettingDao globalSettingDao = new GlobalSettingDaoImpl(connection);
            GlobalSetting globalSetting = globalSettingDao.selectGlobalSetting(companyId);

            return BeanUtils.copyProperties(GlobalSettingDTO.class, globalSetting);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    @Override
    public void transferData(List<Integer> companyIds) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            TransferDao transferDao = new TransferDaoImpl(connection);


            for (Integer companyId : companyIds) {
                try {
                    transferMoney(connection, transferDao, companyId);
//                    transferGroup(transferDao, companyId);
                } catch (Throwable throwable) {
                    logger.error("公司{}迁移数据出错", companyId);
                    logger.error(throwable.getMessage(), throwable);
                }
            }
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

    private void transferGroup(TransferDao transferDao, Integer companyId) throws SQLException {
        List<GroupContent> values = transferDao.selectAllGroupContentValue(companyId);
        if (Utils.isEmpty(values)) {
            logger.info("公司没有组件集数据");
            return;
        }
        List<ComponentGroup> groups = transferDao.selectAllGroup(companyId);
        Map<Integer, ComponentGroup> groupMap = groups.stream().collect(Collectors.toMap(ComponentGroup::getId, c -> c, (a, b) -> b));

        for (GroupContent value : values) {
            ComponentGroup componentGroup = groupMap.get(value.getGroupId());
            Map<Integer, Component> componentMap = componentGroup.getComponents().stream().collect(Collectors.toMap(Component::getNum, c -> c, (a, b) -> b));
            for (Component component : value.getValue()) {
                Component group = componentMap.get(component.getNum());
                component.setType(group.getType());
                component.setName(group.getName());
            }
        }
        transferDao.updateGroupContentValue(values);
    }

    private void transferMoney(Connection connection, TransferDao transferDao, Integer companyId) throws SQLException {
        List<Template> templates = transferDao.selectAllTemplateByType(companyId);
        List<Request> requests = transferDao.selectAllRequestByType(companyId);
        Map<Integer, Template> templateMap = templates.stream().collect(Collectors.toMap(Template::getTemplateId, t -> t, (a, b) -> b));
        Map<Integer, Request> requestMap = RequestUtils.getRequestMap(requests);
        Map<Integer, List<TemplateComponent>> componentMap = transferDao.selectAllComponents(companyId);
        Map<Integer, Map<Integer, List<GroupContent>>> groupComponentMap = transferDao.selectGroupComponent(companyId);


        List<Money> list = new ArrayList<>();
        for (Map.Entry<Integer, List<TemplateComponent>> entry : componentMap.entrySet()) {
            if (!requestMap.containsKey(entry.getKey())) {
                continue;
            }
            Request request = requestMap.get(entry.getKey());
            Template template = templateMap.get(request.getTemplateId());
            List<TemplateComponent> merge = ComponentUtils.mergeComponents(JSONObject.parseArray(template.getTemplateComponent(), TemplateComponent.class), entry.getValue());
            merge = merge.stream().filter(c -> StringUtils.isNotEmpty(c.getValue())).collect(Collectors.toList());
            request.setComponentsContent(merge);

            List<TemplateComponent> moneys = ComponentUtils.getComponentByType(request.getComponentsContent(), ContentType.MONEY);
            List<TemplateComponent> groups = ComponentUtils.getComponentByType(request.getComponentsContent(), ContentType.COMPONENT_GROUP);
            List<TemplateComponent> sums = ComponentUtils.getComponentByType(request.getComponentsContent(), ContentType.TOTAL_MONEY);

            if (Utils.isNotEmpty(sums)) {
                logger.info("有金额汇总组件");
                for (TemplateComponent component : sums) {
                    if (StringUtils.isEmpty(component.getValue())) {
                        continue;
                    }
                    BigDecimal amount = new BigDecimal(component.getValue());
                    if (BigDecimal.ZERO.compareTo(amount) == 0) {
                        continue;
                    }
                    Money money = new Money();
                    money.setCompanyId(companyId);
                    money.setCompanyInfoId(request.getApplicantCiid());
                    money.setRequestId(request.getRequestDkey());
                    money.setTemplateName(template.getTemplateName());
                    money.setNum(component.getNum());
                    money.setName(component.getName());
                    money.setAmount(amount);
                    money.setIsSum(1);
                    money.setCreateTime(request.getCreateTime());
                    money.setApprovalNum(request.getApprovalNum());
                    if (Objects.equals(String.valueOf(component.getNum()), template.getRelateAnalysisNum())) {
                        money.setIsRelatedToAmoeba(1);
                        money.setIsRelatedToCost(1);
                    } else {
                        money.setIsRelatedToAmoeba(0);
                        money.setIsRelatedToCost(0);
                    }
                    if (request.getFinished() > 0 && request.getFinished() < 3) {
                        money.setState(1);
                    } else {
                        money.setState(2);
                    }
                    list.add(money);
                }
                if (Utils.isNotEmpty(list)) {
                    request.setMoneys(list);
                }
                continue;
            }

            if (Utils.isNotEmpty(moneys)) {
                for (TemplateComponent component : moneys) {
                    if (StringUtils.isEmpty(component.getValue())) {
                        continue;
                    }
                    BigDecimal amount ;
                    try {
                        amount = new BigDecimal(component.getValue());
                    } catch (Exception e) {
                        logger.error("出错的金额:{}", JSONObject.toJSONString(component));
                        continue;
                    }
                    if (BigDecimal.ZERO.compareTo(amount) == 0) {
                        continue;
                    }
                    Money money = new Money();
                    money.setCompanyId(companyId);
                    money.setCompanyInfoId(request.getApplicantCiid());
                    money.setRequestId(request.getRequestDkey());
                    money.setTemplateName(template.getTemplateName());
                    money.setNum(component.getNum());
                    money.setName(component.getName());
                    money.setAmount(amount);
                    money.setIsSum(0);
                    money.setCreateTime(request.getCreateTime());
                    money.setApprovalNum(request.getApprovalNum());
                    if (Objects.equals(String.valueOf(component.getNum()), template.getRelateAnalysisNum())) {
                        money.setIsRelatedToAmoeba(1);
                        money.setIsRelatedToCost(1);
                    } else {
                        money.setIsRelatedToAmoeba(0);
                        money.setIsRelatedToCost(0);
                    }
                    if (request.getFinished() > 0 && request.getFinished() < 3) {
                        money.setState(1);
                    } else {
                        money.setState(2);
                    }
                    list.add(money);
                }
            }
            if (Utils.isNotEmpty(groups)) {
                for (TemplateComponent group : groups) {
                    List<GroupContent> groupContents = groupComponentMap.get(request.getRequestDkey()).get(group.getNum());
                    if (Utils.isNull(groupContents)) {
                        logger.info("出错的id:{}", request.getRequestDkey());
                        continue;
                    }
                    for (GroupContent groupContent : groupContents) {
                        List<Component> components = groupContent.getValue();
                        for (Component component : components) {
                            if (component.getType() != ContentType.MONEY) {
                                continue;
                            }
                            if (StringUtils.isEmpty(component.getValue())) {
                                continue;
                            }
                            BigDecimal amount = new BigDecimal(component.getValue());
                            if (BigDecimal.ZERO.compareTo(amount) == 0) {
                                continue;
                            }
                            Money money = new Money();
                            money.setCompanyId(companyId);
                            money.setCompanyInfoId(request.getApplicantCiid());
                            money.setRequestId(request.getRequestDkey());
                            money.setTemplateName(template.getTemplateName());
                            money.setNum(group.getNum());
                            money.setName(group.getName());
                            money.setSubNum(component.getNum());
                            money.setSubName(component.getName());
                            money.setAmount(amount);
                            money.setIsSum(0);
                            money.setCreateTime(request.getCreateTime());
                            money.setApprovalNum(request.getApprovalNum());
                            if (Objects.equals(String.valueOf(group.getNum()), template.getRelateAnalysisNum())) {
                                money.setIsRelatedToAmoeba(1);
                                money.setIsRelatedToCost(1);
                            } else {
                                money.setIsRelatedToAmoeba(0);
                                money.setIsRelatedToCost(0);
                            }
                            if (request.getFinished() > 0 && request.getFinished() < 3) {
                                money.setState(1);
                            } else {
                                money.setState(2);
                            }
                            list.add(money);
                        }
                    }
                }
            }
            if (Utils.isNotEmpty(list)) {
                request.setMoneys(list);
            }
        }

        if (Utils.isNotEmpty(list)) {
            DBUtils.begin(connection);
            transferDao.insertMoneys(list);
            DBUtils.commit(connection);
        }
    }


    @Override
    public Integer getRequestStatusById(Integer id) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            SelectApprovalDao selectApprovalDao = new SelectApprovalDaoImpl(connection);

            return selectApprovalDao.selectRequestNewestStatus(id);
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }


    @Override
    public void updateGlobalSetting(GlobalSettingDTO globalSettingDTO) throws Throwable {
        Connection connection = DBUtils.getConnection(DbName.APPROVALREQ);
        try {
            DBUtils.begin(connection);

            GlobalSettingDao globalSettingDao = new GlobalSettingDaoImpl(connection);
            GlobalSetting globalSetting = BeanUtils.copyProperties(GlobalSetting.class, globalSettingDTO);

            globalSettingDao.updateDuplicateStrategy(globalSetting);

            DBUtils.commit(connection);
        } catch (Throwable e) {
            DBUtils.rollback(connection);
            logger.error(e.getMessage(), e);
            throw ErrorUtils.throwError(e);
        } finally {
            DBUtils.release(connection);
        }
    }

}
